package q1.project.core.jpa.config;

import java.lang.reflect.Field;
import java.util.List;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.springframework.stereotype.Component;
import q1.project.core.jpa.annotation.Comment;

/**
 * Hibernate Comment 注解集成器 用于处理 @Comment 注解，为数据库表和字段添加注释
 *
 * @author Elyar Adil
 * @author Q1 Team
 * @since 1.0
 */
@Component
public class CommentIntegrator implements Integrator {
  public static final CommentIntegrator INSTANCE = new CommentIntegrator();

  public CommentIntegrator() {
    super();
  }

  /** 执行注释集成 */
  @Override
  public void integrate(
      Metadata metadata,
      BootstrapContext bootstrapContext,
      SessionFactoryImplementor sessionFactory) {
    processComment(metadata);
  }

  /**
   * 反集成（未使用）
   *
   * @param sessionFactoryImplementor The session factory being closed.
   * @param sessionFactoryServiceRegistry That session factory's service registry
   */
  @Override
  public void disintegrate(
      SessionFactoryImplementor sessionFactoryImplementor,
      SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {}

  /**
   * 处理 Comment 注解
   *
   * @param metadata process annotation of this {@code Metadata}.
   */
  private void processComment(Metadata metadata) {
    for (PersistentClass persistentClass : metadata.getEntityBindings()) {
      // 处理类级别的 Comment 注解
      Class<?> clz = persistentClass.getMappedClass();
      if (clz.isAnnotationPresent(Comment.class)) {
        Comment comment = clz.getAnnotation(Comment.class);
        persistentClass.getTable().setComment(comment.value());
      }

      // 处理主键的 Comment 注解
      Property identifierProperty = persistentClass.getIdentifierProperty();
      if (identifierProperty != null) {
        fieldComment(persistentClass, identifierProperty.getName());
      } else {
        org.hibernate.mapping.Component component = persistentClass.getIdentifierMapper();
        if (component != null) {
          // noinspection unchecked
          List<Property> iterator = component.getProperties();
          for (Property property : iterator) {
            fieldComment(persistentClass, property.getName());
          }
        }
      }

      // 处理字段的 Comment 注解
      // noinspection unchecked
      List<Property> iterator = persistentClass.getProperties();
      for (Property property : iterator) {
        fieldComment(persistentClass, property.getName());
      }
    }
  }

  /**
   * 处理字段的 @Comment 注解
   *
   * @param persistentClass Hibernate {@code PersistentClass}
   * @param columnName 字段名
   */
  private void fieldComment(PersistentClass persistentClass, String columnName) {
    try {
      // 获取字段
      Field field = findField(persistentClass.getMappedClass(), columnName);
      if (field == null) {
        return;
      }

      // 检查是否存在 Comment 注解
      if (field.isAnnotationPresent(Comment.class)) {
        String comment = field.getAnnotation(Comment.class).value();

        // 获取属性
        Property property = persistentClass.getProperty(columnName);
        if (property == null) {
          return;
        }

        // 获取列信息
        List<Column> columns = property.getValue().getColumns();
        if (columns.isEmpty()) {
          return;
        }

        String sqlColumnName = columns.get(0).getName();

        // 遍历表中的列并设置注释
        for (Column column : persistentClass.getTable().getColumns()) {
          if (sqlColumnName.equalsIgnoreCase(column.getName())) {
            column.setComment(comment);
          }
        }
      }
    } catch (SecurityException e) {
      // 忽略安全异常
    }
  }

  /** 递归查找字段（包括父类） */
  private Field findField(Class<?> clazz, String fieldName) {
    if (clazz == null) {
      return null;
    }

    try {
      return clazz.getDeclaredField(fieldName);
    } catch (NoSuchFieldException e) {
      // 递归查找父类
      return findField(clazz.getSuperclass(), fieldName);
    }
  }
}
